#include "protocol_oop.h"

protocol_oop::protocol_oop()
{

}
INT32U protocol_oop::cosem_bin2_unit(INT8U *bin, INT8U size)
{
   INT16S idx;
   INT32U val=0;

   for (idx=0; idx<size; idx++)
   {
       val <<= 8;
       val += bin[idx];
   }
   return val;
}
INT16U  protocol_oop::get_cosem_data_len(INT8U *data, INT8U *len_size)
{
    INT16U num;

    if (data[0] & 0x80)
    {
        num=cosem_bin2_unit(data+1,data[0]& 0x7F);
        *len_size=(data[0]& 0x7F)+1;
    }
    else
    {
        num=data[0];
        *len_size=1;
    }

    return num;

}
INT16U protocol_oop::set_cosem_data_len(INT8U *data,INT16U len)
{

    if(len >= 0x80)
    {
        data[0] = 0x81;
        if(len > 255)
        {
            data[0]++;
            data[1] = len>>8;
            data[2] = len;
            return 3;
        }
        else
        {
            data[1] = len;
            return 2;
        }
    }
    else
    {
        data[0] = len;
    }
    return 1;
}

/*
* Calculate a new fcs given the current fcs and the new data.
*/
INT16U pppfcs16_Inner(INT16U fcs, INT8U *cp, INT16S len)
{


   while(len--)
   {
      fcs = (fcs >> 8) ^ fcstab_Inner[(fcs ^ *cp++) & 0xff];
   }
   return (fcs);
}
void fcs16(INT8U *frame, INT16S len)
{
   INT16U trialfcs;

   /* add on output */
   trialfcs = pppfcs16_Inner( PPPINITFCS16, frame, len );
   trialfcs ^= 0xffff; /* complement */
   frame[len] = (trialfcs & 0x00ff); /* least significant byte first */
   frame[len+1] = ((trialfcs >> 8) & 0x00ff);
}
INT16U fcs16_16u(INT8U *frame, INT16S len)
{
    INT16U trialfcs;

    /* add on output */
    trialfcs = pppfcs16_Inner( PPPINITFCS16, frame, len );
    trialfcs ^= 0xffff; /* complement */
    return trialfcs;
}
INT16U protocol_oop::makeOOP0907UpdateFrame(INT8U  *buf,INT16U buf_len,INT8U *resp)
{
    INT16U pos =0;
    INT8U head_len =0;
    resp[pos++] = 0x68;
    pos+=2;  //跳过长度
    resp[pos++] = 0x43;
    resp[pos++] = 0x5; //地址长度
    memcpy(resp+pos,"\x88\x18\x11\x11\x11\x11",6);
    pos+=6;
    resp[pos++] = 0x10; // 主站
    pos+=2;  //跳过校验
    resp[pos++] = 0x09;
    resp[pos++] = 0x07;
    resp[pos++] = 0x0A;
    memcpy(resp+pos,"\xF2\x0B\x02\x01\x03\x02\x08\x01\x00\x00\x0A\x03\xE8",13);//转发端口参数
    pos+=13;
    pos+=set_cosem_data_len(resp+pos,buf_len);
    memcpy(resp+pos,buf,buf_len);
    pos+= buf_len;
    resp[pos++] = 0x00; //时间标签。
    head_len = 3 + 6 + 2;
    //3.4 设置长度
    resp[OOP_POS_LEN] = pos-1+2;
    resp[OOP_POS_LEN+1] = (pos-1+2) >> 8;
    fcs16(resp+OOP_POS_LEN, head_len);
    //计算FCS校验位
    fcs16(resp+OOP_POS_LEN, pos-1);
   pos += 2;
    resp[pos++] = 0x16;
    return pos;
}
INT8U* trim_oopframe_FE(INT8U* frame)
{
    INT8U *old_frame;
    INT8U idx=0;

    old_frame=frame;
    while (idx<8)
    {
        if (*frame==0x68)
        {
            return frame;
        }
        frame++;
        idx++;
    }
    return old_frame;
}
INT8U get_oopframe_addr_length(INT8U* frame)
{
    INT8U addr_len;

    frame = trim_oopframe_FE(frame);

    addr_len = 0;
    if (0x68 != frame[OOP_POS_BEGIN]) return addr_len;
    addr_len=(frame[OOP_POS_ADDR] & 0x0F)+3;
    return addr_len;
}
INT8U protocol_oop::check_frame_header_gb_oop(INT8U *frame)
{
    INT16U hcs;
    INT8U addr_len;


//    frame = trim_oopframe_FE(frame);
    addr_len = get_oopframe_addr_length(frame);
    if((addr_len == 0) || (addr_len>16)) return FALSE;
    //计算HCS校验位
    hcs = fcs16_16u(frame+OOP_POS_LEN,addr_len+3);
    if (hcs != bin2_int16u(frame+OOP_POS_ADDR+addr_len)) return FALSE;
    return TRUE;
}

INT8U protocol_oop::check_frame_body_gb_oop(INT8U* frame,INT16U recv_len)
{

    INT16U hcs,fcs,f_len;
    INT8U addr_len;

//    frame = trim_oopframe_FE(frame);
    addr_len = get_oopframe_addr_length(frame);
    if (addr_len == 0) return 0;
    //计算HCS校验位
    hcs = fcs16_16u(frame+OOP_POS_LEN,addr_len+3);
    if (hcs != bin2_int16u(frame+OOP_POS_ADDR+addr_len))
        return FALSE;

    f_len = frame[OOP_POS_LEN] + ((frame[OOP_POS_LEN+1] )<<8);
    //计算FCS校验位
    fcs = fcs16_16u(frame+OOP_POS_LEN,f_len-2);
    if (fcs != bin2_int16u(frame+OOP_POS_LEN+f_len-2))
        return FALSE;
    if (frame[OOP_POS_LEN+f_len] != 0x16)
        return FALSE;
    return TRUE;
}

